﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace YCopy
{

    public partial class Form1 : Form
    {

        bool _showLog = false;
        bool _started = false;
        bool _paused = false;
        int _allFileCount = 0;
        int _finished = 0;
        int _error = 0;

        public Form1()
        {
            InitializeComponent();
        }

        void CopyDirectorysAndFiles(string dest, DirectoryInfo srcdir, bool copySrcDir)
        {
            if (dest.LastIndexOf('\\') != (dest.Length - 1))
            {
                dest += "\\";
            }

            if (copySrcDir)
            {
                dest = dest + srcdir.Name + '\\';
            }
            if (!Directory.Exists(dest))
            {
                Directory.CreateDirectory(dest);
            }
            FileInfo[] files = srcdir.GetFiles();
            foreach (FileInfo file in files)
            {
                while (_paused)
                {
                    Thread.Sleep(100);
                }
                try
                {
                    file.CopyTo(dest + file.Name, true);
                    if (_showLog)
                    {
                        string msg = file.FullName;
                        Invoke(new Action(() => AddShowText(msg)));
                    }
                }
                catch (IOException ex)
                {
                    _error++;
                    string errMsg = ex.Message + "\t" + file.FullName;
                    Log.Add(errMsg);
                    Invoke(new Action(() => AddShowText(errMsg)));
                }
                _finished++;
                if (_finished % (Math.Max(1, _allFileCount / 100)) == 0)
                {
                    backgroundWorker1.ReportProgress(Math.Min(100, _finished * 100 / _allFileCount));
                }
            }
            DirectoryInfo[] dirs = srcdir.GetDirectories();
            foreach (DirectoryInfo dirInfo in dirs)
            {
                try
                {
                    CopyDirectorysAndFiles(dest, dirInfo, true);
                }
                catch (IOException ex)
                {
                    string errMsg = ex.Message + "\t" + dirInfo.FullName;
                    Log.Add(errMsg);
                    Invoke(new Action(() => AddShowText(errMsg)));
                }
            }
        }

        void AddShowText(string msg)
        {
            txtLog.Text += DateTime.Now.ToString("HH:mm:ss ") + msg + Environment.NewLine;
            txtLog.SelectionStart = txtLog.Text.Length;
            txtLog.SelectionLength = 0;
            txtLog.ScrollToCaret();
        }

        int GetFileCount(DirectoryInfo dir)
        {
            int cnt = 0;
            cnt = dir.GetFiles().Length;
            foreach (DirectoryInfo dirInfo in dir.GetDirectories())
            {
                try
                {
                    cnt += GetFileCount(dirInfo);
                }
                catch (IOException ex)
                {
                    Log.Add(ex.Message);
                }
            }
            return cnt;
        }

        private void btnBrowseSource_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                txtSourceDir.Text = folderBrowserDialog1.SelectedPath;
            }
        }

        private void btnCopy_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(txtDestDir.Text))
            {
                MessageBox.Show("请指定目标目录");
                txtDestDir.Focus();
                return;
            }
            if (String.IsNullOrEmpty(txtSourceDir.Text))
            {
                MessageBox.Show("请指定源目录");
                txtSourceDir.Focus();
                return;
            }

            _started = true;
            _paused = false;
            SetButton();
            pgCopyProgress.Style = ProgressBarStyle.Marquee;
            pgCopyProgress.Value = 0;
            AddShowText("正在计算文件数量...");
            SetButton();
            Thread t = new Thread(new ThreadStart(() =>
            {
                _allFileCount = GetFileCount(new DirectoryInfo(txtSourceDir.Text));
                Invoke(new Action(() =>
                {
                    AddShowText("共有" + _allFileCount + "个文件待复制");
                    AddShowText("正在复制...");
                    pgCopyProgress.Style = ProgressBarStyle.Continuous;
                    backgroundWorker1.RunWorkerAsync();
                }));
            }));
            t.Start();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void btnBrowseDest_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                txtDestDir.Text = folderBrowserDialog1.SelectedPath;
            }
        }

        private void btnLog_Click(object sender, EventArgs e)
        {
            Log.Show();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            CopyDirectorysAndFiles(txtDestDir.Text, new DirectoryInfo(txtSourceDir.Text), false);
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            pgCopyProgress.Value = e.ProgressPercentage;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _paused = true;
            _started = false;
            AddShowText("复制完成! 共复制" + _finished + "个文件");
            SetButton();
        }

        void SetButton()
        {
            btnCopy.Enabled = !_started;
            btnPause.Text = _paused ? "继续" : "暂停";
            btnPause.Enabled = _started;
            pgCopyProgress.Visible = _started;
        }

        class Log
        {
            static string _logFile = Path.Combine(Application.StartupPath, DateTime.Now.ToString("MMddHHmmss") + ".log");
            public DateTime LogTime;
            public string LogMessage;

            static List<Log> Logs = new List<Log>();

            private Log()
            {

            }

            public static void Add(string msg)
            {
                Logs.Add(new Log() { LogTime = DateTime.Now, LogMessage = msg });
            }

            public static void Save()
            {
                if (Logs.Count == 0) return;
                StreamWriter sw = new StreamWriter(_logFile);
                foreach (var log in Logs)
                {
                    sw.WriteLine(String.Format("{0:HH:mm:ss}\t{1}", log.LogTime, log.LogMessage));
                }
                sw.Close();
            }

            public static void Show()
            {
                Save();
                Process.Start(_logFile);
            }
        }

        private void btnShow_Click(object sender, EventArgs e)
        {
            _showLog = !_showLog;
        }

        private void btnPause_Click(object sender, EventArgs e)
        {
            _paused = !_paused;
            SetButton();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Log.Save();
        }

    }
}
